
from utils import *

import random
import socket
import sys
import thread
from types import *

import game

class Server:
    def __init__(self, host='0.0.0.0', port=1337, debug=False):
        self.mutex = thread.allocate_lock()
        self.games = {} #map from game's name to game
        self.host  = host
        self.port  = port
        self.debug = debug
        return
    
    def lock(self):
        self.mutex.acquire()
        return
    def unlock(self):
        self.mutex.release()
        return
    def locked(self):
        return self.mutex.locked()
    
    def run(self):
        self.sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
        self.sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
        self.sock.bind((self.host,self.port))
        self.sock.listen(5)
        running = True
        while running:
            sock, addr = self.sock.accept()
            thread.start_new_thread(clientthread, (sock, addr, self, self.debug))
        return
    
    def gamesmessage(self):
        s = [g for g in self.games]
        s.sort()
        s = [g+','+self.games[g].type for g in s]
        return ''.join(['{']+[','.join(s)]+['}'])
    
    def newgame(self, name, type):
        assert name not in self.games
        g = game.newgame(name, type)
        g.server = self
        self.games[name] = g
        return g
    
    def endgame(self, name):
        if name in self.games:
            del self.games[name]
        return
    

def clientthread(sock, addr, server, debug=False):
    '''
    
    {playername}
    
    {gamename,gametype,...}
    
    {gamename,gametype,role}
    
    '''
    for i in xrange(1):
    #try:
        s = sure_recv(sock, '{')
        name = delim_recv(sock, ['}'])
        if debug:
            print name
        server.lock()
        s = server.gamesmessage()
        server.unlock()
        if debug:
            print s
        sure_send(sock, s)
        s = sure_recv(sock, '{')
        gname = delim_recv(sock, [','])
        gtype = delim_recv(sock, [','])
        role  = delim_recv(sock, ['}'])
        if debug:
            print gname, gtype, role
        server.lock()
        if gname in server.games:
            g = server.games[gname]
        else:
            g = server.newgame(gname, gtype)
        server.unlock()
        assert g is not None
#        assert g.type == gtype
        r = g.playerjoin(name, role)
        if not r:
            break
        try:
            while True:
                s = g.getmessage(name)
                if debug:
                    print name+' <- '+s
                sure_send(sock, s)
            #try:
                s = sure_recv(sock, '{')
                s = delim_recv(sock, ['}'])
            #except:
            #    g.abort()
                if debug:
                    print name+' -> '+s[1:]
                g.playermessage(name, s)        
        except:
            g.abort()
    #except:
    #    pass
    sock.close()
    return


def main():
    host  = '0.0.0.0'
    port  = 1337
    debug = False
    
    if '--host' in sys.argv:
        host = sys.argv[index('--host')+1]
    if '--port' in sys.argv:
        port = int(sys.argv[index('--port')+1])
    if '--debug' in sys.argv:
        debug=True
        
    s = Server(host, port, debug)
    return s.run()

if __name__ == '__main__':
    # Import Psyco if available
    try:
        import psyco
        psyco.full()
    except ImportError:
        print 'psyco not available'
    
    main()











